home *** CD-ROM | disk | FTP | other *** search
/ Aminet 45 / Aminet 45 (2001)(GTI - Schatztruhe)[!][Oct 2001].iso / Aminet / gfx / x11 / x3270_3_2_16.lha / amiga_src / ft.c < prev    next >
C/C++ Source or Header  |  2001-06-23  |  55KB  |  2,070 lines

  1. /*
  2.  * Modifications Copyright 1996, 1999, 2000 by Paul Mattes.
  3.  * Copyright October 1995 by Dick Altenbern.
  4.  * Based in part on code Copyright 1993, 1994, 1995 by Paul Mattes.
  5.  *  Permission to use, copy, modify, and distribute this software and its
  6.  *  documentation for any purpose and without fee is hereby granted,
  7.  *  provided that the above copyright notice appear in all copies and that
  8.  *  both that copyright notice and this permission notice appear in
  9.  *  supporting documentation.
  10.  */
  11.  
  12. /*
  13.  *    ft.c
  14.  *        This module handles the file transfer dialogs.
  15.  */
  16.  
  17. #include "globals.h"
  18.  
  19. #if defined(X3270_FT) /*[*/
  20.  
  21. #if defined(X3270_DISPLAY) /*[*/
  22. #include <X11/StringDefs.h>
  23. #include <X11/Xaw/Toggle.h>
  24. #include <X11/Xaw/Command.h>
  25. #include <X11/Xaw/Form.h>
  26. #include <X11/Shell.h>
  27. #include <X11/Xaw/AsciiText.h>
  28. #include <X11/Xaw/TextSrc.h>
  29. #include <X11/Xaw/TextSink.h>
  30. #include <X11/Xaw/AsciiSrc.h>
  31. #include <X11/Xaw/AsciiSink.h>
  32. #endif /*]*/
  33. #include <errno.h>
  34.  
  35. #include "appres.h"
  36. #include "actionsc.h"
  37. #include "ft_cutc.h"
  38. #include "ft_dftc.h"
  39. #include "ftc.h"
  40. #include "hostc.h"
  41. #include "kybdc.h"
  42. #include "macrosc.h"
  43. #include "objects.h"
  44. #include "popupsc.h"
  45. #include "telnetc.h"
  46. #include "utilc.h"
  47.  
  48. /* Macros. */
  49. #define eos(s)    strchr((s), '\0')
  50.  
  51. #if defined(X3270_DISPLAY) /*[*/
  52. #define FILE_WIDTH    300    /* width of file name widgets */
  53. #define MARGIN        3    /* distance from margins to widgets */
  54. #define CLOSE_VGAP    0    /* distance between paired toggles */
  55. #define FAR_VGAP    10    /* distance between single toggles and groups */
  56. #define BUTTON_GAP    5    /* horizontal distance between buttons */
  57. #define COLUMN_GAP    40    /* distance between columns */
  58. #endif /*]*/
  59.  
  60. #define BN    (Boolean *)NULL
  61.  
  62. /* Externals. */
  63. #if defined(X3270_DISPLAY) && defined(X3270_MENUS) /*[*/
  64. extern Pixmap diamond;
  65. extern Pixmap no_diamond;
  66. extern Pixmap null;
  67. extern Pixmap dot;
  68. #endif /*]*/
  69.  
  70. /* Globals. */
  71. enum ft_state ft_state = FT_NONE;    /* File transfer state */
  72. char *ft_local_filename;        /* Local file to transfer to/from */
  73. FILE *ft_local_file = (FILE *)NULL;    /* File descriptor for local file */
  74. Boolean ascii_flag = True;        /* Convert to ascii */
  75. Boolean cr_flag = True;            /* Add crlf to each line */
  76. Boolean remap_flag = True;        /* Remap ASCII<->EBCDIC */
  77. unsigned long ft_length = 0;        /* Length of transfer */
  78.  
  79. /* Statics. */
  80. #if defined(X3270_DISPLAY) && defined(X3270_MENUS) /*[*/
  81. static Widget ft_dialog, ft_shell, local_file, host_file;
  82. static Widget lrecl_widget, blksize_widget;
  83. static Widget primspace_widget, secspace_widget;
  84. static Widget send_toggle, receive_toggle;
  85. static Widget vm_toggle, tso_toggle;
  86. static Widget ascii_toggle, binary_toggle;
  87. static Widget cr_widget;
  88. static Widget remap_widget;
  89. #endif /*]*/
  90.  
  91. static char *ft_host_filename;        /* Host file to transfer to/from */
  92. static Boolean receive_flag = True;    /* Current transfer is receive */
  93. static Boolean append_flag = False;    /* Append transfer */
  94. static Boolean vm_flag = False;        /* VM Transfer flag */
  95.  
  96. #if defined(X3270_DISPLAY) && defined(X3270_MENUS) /*[*/
  97. struct toggle_list {            /* List of toggle widgets */
  98.     Widget *widgets;
  99. };
  100. static Widget recfm_options[5];
  101. static Widget units_options[5];
  102. static struct toggle_list recfm_toggles = { recfm_options };
  103. static struct toggle_list units_toggles = { units_options };
  104. #endif /*]*/
  105.  
  106. static enum recfm {
  107.     DEFAULT_RECFM, FIXED, VARIABLE, UNDEFINED
  108. } recfm = DEFAULT_RECFM;
  109. #if defined(X3270_DISPLAY) && defined(X3270_MENUS) /*[*/
  110. static Boolean recfm_default = True;
  111. static enum recfm r_default_recfm = DEFAULT_RECFM;
  112. static enum recfm r_fixed = FIXED;
  113. static enum recfm r_variable = VARIABLE;
  114. static enum recfm r_undefined = UNDEFINED;
  115. #endif /*]*/
  116.  
  117. static enum units {
  118.     DEFAULT_UNITS, TRACKS, CYLINDERS, AVBLOCK
  119. } units = DEFAULT_UNITS;
  120. #if defined(X3270_DISPLAY) && defined(X3270_MENUS) /*[*/
  121. static Boolean units_default = True;
  122. static enum units u_default_units = DEFAULT_UNITS;
  123. static enum units u_tracks = TRACKS;
  124. static enum units u_cylinders = CYLINDERS;
  125. static enum units u_avblock = AVBLOCK;
  126. #endif /*]*/
  127.  
  128. typedef enum { T_NUMERIC, T_HOSTFILE, T_UNIXFILE } text_t;
  129. #if defined(X3270_DISPLAY) && defined(X3270_MENUS) /*[*/
  130. static text_t t_numeric = T_NUMERIC;
  131. static text_t t_hostfile = T_HOSTFILE;
  132. static text_t t_unixfile = T_UNIXFILE;
  133. #endif /*]*/
  134.  
  135. #if defined(X3270_DISPLAY) && defined(X3270_MENUS) /*[*/
  136. static Boolean s_true = True;
  137. static Boolean s_false = False;
  138. #endif /*]*/
  139. static Boolean allow_overwrite = False;
  140. #if defined(X3270_DISPLAY) && defined(X3270_MENUS) /*[*/
  141. typedef struct sr {
  142.     struct sr *next;
  143.     Widget w;
  144.     Boolean *bvar1;
  145.     Boolean bval1;
  146.     Boolean *bvar2;
  147.     Boolean bval2;
  148.     Boolean *bvar3;
  149.     Boolean bval3;
  150.     Boolean is_value;
  151.     Boolean has_focus;
  152. } sr_t;
  153. static sr_t *sr = (sr_t *)NULL;
  154. static sr_t *sr_last = (sr_t *)NULL;
  155.  
  156. static Widget progress_shell, from_file, to_file;
  157. static Widget ft_status, waiting, aborting;
  158. static String status_string;
  159. #endif /*]*/
  160. static struct timeval t0;        /* Starting time */
  161. static Boolean ft_is_cut;        /* File transfer is CUT-style */
  162.  
  163. #if defined(X3270_DISPLAY) && defined(X3270_MENUS) /*[*/
  164. static Widget overwrite_shell;
  165. #endif /*]*/
  166. static Boolean ft_is_action;
  167.  
  168. #if defined(X3270_DISPLAY) && defined(X3270_MENUS) /*[*/
  169. static void apply_bitmap(Widget w, Pixmap p);
  170. static void check_sensitivity(Boolean *bvar);
  171. static void flip_toggles(struct toggle_list *toggle_list, Widget w);
  172. static void focus_next(sr_t *s);
  173. static void ft_cancel(Widget w, XtPointer client_data, XtPointer call_data);
  174. static void ft_popup_callback(Widget w, XtPointer client_data,
  175.     XtPointer call_data);
  176. static void ft_popup_init(void);
  177. static int ft_start(void);
  178. static void ft_start_callback(Widget w, XtPointer call_parms,
  179.     XtPointer call_data);
  180. static void match_dimension(Widget w1, Widget w2, const char *n);
  181. static void overwrite_cancel_callback(Widget w, XtPointer client_data,
  182.     XtPointer call_data);
  183. static void overwrite_okay_callback(Widget w, XtPointer client_data,
  184.     XtPointer call_data);
  185. static void overwrite_popdown(Widget w, XtPointer client_data,
  186.     XtPointer call_data);
  187. static void overwrite_popup_init(void);
  188. static void popup_overwrite(void);
  189. static void popup_progress(void);
  190. static void progress_cancel_callback(Widget w, XtPointer client_data,
  191.     XtPointer call_data);
  192. static void progress_popup_callback(Widget w, XtPointer client_data,
  193.     XtPointer call_data);
  194. static void progress_popup_init(void);
  195. static void recfm_callback(Widget w, XtPointer user_data, XtPointer call_data);
  196. static void register_sensitivity(Widget w, Boolean *bvar1, Boolean bval1,
  197.     Boolean *bvar2, Boolean bval2, Boolean *bvar3, Boolean bval3);
  198. static void text_callback(Widget w, XtPointer client_data, XtPointer call_data);
  199. static void toggle_append(Widget w, XtPointer client_data, XtPointer call_data);
  200. static void toggle_ascii(Widget w, XtPointer client_data, XtPointer call_data);
  201. static void toggle_cr(Widget w, XtPointer client_data, XtPointer call_data);
  202. static void toggle_remap(Widget w, XtPointer client_data, XtPointer call_data);
  203. static void toggle_receive(Widget w, XtPointer client_data,
  204.     XtPointer call_data);
  205. static void toggle_vm(Widget w, XtPointer client_data, XtPointer call_data);
  206. static void units_callback(Widget w, XtPointer user_data, XtPointer call_data);
  207. #endif /*]*/
  208. static void ft_connected(Boolean ignored);
  209. static void ft_in3270(Boolean ignored);
  210.  
  211. /* Main external entry point. */
  212.  
  213. #if !defined(X3270_DISPLAY) || !defined(X3270_MENUS) /*[*/
  214. void
  215. ft_init(void)
  216. {
  217.     /* Register for state changes. */
  218.     register_schange(ST_CONNECT, ft_connected);
  219.     register_schange(ST_3270_MODE, ft_in3270);
  220. }
  221. #endif /*]*/
  222.  
  223. #if defined(X3270_DISPLAY) && defined(X3270_MENUS) /*[*/
  224. /* "File Transfer" dialog. */
  225.  
  226. /*
  227.  * Pop up the "Transfer" menu.
  228.  * Called back from the "File Transfer" option on the File menu.
  229.  */
  230. void
  231. popup_ft(Widget w unused, XtPointer call_parms unused,
  232.     XtPointer call_data unused)
  233. {
  234.     /* Initialize it. */
  235.     if (ft_shell == (Widget)NULL)
  236.         ft_popup_init();
  237.  
  238.     /* Pop it up. */
  239.     popup_popup(ft_shell, XtGrabNone);
  240. }
  241.  
  242. /* Initialize the transfer pop-up. */
  243. static void
  244. ft_popup_init(void)
  245. {
  246.     Widget w;
  247.     Widget cancel_button;
  248.     Widget local_label, host_label;
  249.     Widget append_widget;
  250.     Widget lrecl_label, blksize_label, primspace_label, secspace_label;
  251.     Widget h_ref = (Widget)NULL;
  252.     Dimension d1;
  253.     Dimension maxw = 0;
  254.     Widget recfm_label, units_label;
  255.     Widget start_button;
  256.  
  257.     /* Register for state changes. */
  258.     register_schange(ST_CONNECT, ft_connected);
  259.     register_schange(ST_3270_MODE, ft_in3270);
  260.  
  261.     /* Create the menu shell. */
  262.     ft_shell = XtVaCreatePopupShell(
  263.         "ftPopup", transientShellWidgetClass, toplevel,
  264.         NULL);
  265.     XtAddCallback(ft_shell, XtNpopupCallback, place_popup,
  266.         (XtPointer)CenterP);
  267.     XtAddCallback(ft_shell, XtNpopupCallback, ft_popup_callback,
  268.         (XtPointer)NULL);
  269.  
  270.     /* Create the form within the shell. */
  271.     ft_dialog = XtVaCreateManagedWidget(
  272.         ObjDialog, formWidgetClass, ft_shell,
  273.         NULL);
  274.  
  275.     /* Create the file name widgets. */
  276.     local_label = XtVaCreateManagedWidget(
  277.         "local", labelWidgetClass, ft_dialog,
  278.         XtNvertDistance, FAR_VGAP,
  279.         XtNhorizDistance, MARGIN,
  280.         XtNborderWidth, 0,
  281.         NULL);
  282.     local_file = XtVaCreateManagedWidget(
  283.         "value", asciiTextWidgetClass, ft_dialog,
  284.         XtNeditType, XawtextEdit,
  285.         XtNwidth, FILE_WIDTH,
  286.         XtNvertDistance, FAR_VGAP,
  287.         XtNfromHoriz, local_label,
  288.         XtNhorizDistance, 0,
  289.         NULL);
  290.     match_dimension(local_label, local_file, XtNheight);
  291.     w = XawTextGetSource(local_file);
  292.     if (w == NULL)
  293.         XtWarning("Cannot find text source in dialog");
  294.     else
  295.         XtAddCallback(w, XtNcallback, text_callback,
  296.             (XtPointer)&t_unixfile);
  297.     register_sensitivity(local_file,
  298.         BN, False,
  299.         BN, False,
  300.         BN, False);
  301.  
  302.     host_label = XtVaCreateManagedWidget(
  303.         "host", labelWidgetClass, ft_dialog,
  304.         XtNfromVert, local_label,
  305.         XtNvertDistance, 3,
  306.         XtNhorizDistance, MARGIN,
  307.         XtNborderWidth, 0,
  308.         NULL);
  309.     host_file = XtVaCreateManagedWidget(
  310.         "value", asciiTextWidgetClass, ft_dialog,
  311.         XtNeditType, XawtextEdit,
  312.         XtNwidth, FILE_WIDTH,
  313.         XtNdisplayCaret, False,
  314.         XtNfromVert, local_label,
  315.         XtNvertDistance, 3,
  316.         XtNfromHoriz, host_label,
  317.         XtNhorizDistance, 0,
  318.         NULL);
  319.     match_dimension(host_label, host_file, XtNheight);
  320.     match_dimension(local_label, host_label, XtNwidth);
  321.     w = XawTextGetSource(host_file);
  322.     if (w == NULL)
  323.         XtWarning("Cannot find text source in dialog");
  324.     else
  325.         XtAddCallback(w, XtNcallback, text_callback,
  326.             (XtPointer)&t_hostfile);
  327.     register_sensitivity(host_file,
  328.         BN, False,
  329.         BN, False,
  330.         BN, False);
  331.  
  332.     /* Create the left column. */
  333.  
  334.     /* Create send/receive toggles. */
  335.     send_toggle = XtVaCreateManagedWidget(
  336.         "send", commandWidgetClass, ft_dialog,
  337.         XtNfromVert, host_label,
  338.         XtNvertDistance, FAR_VGAP,
  339.         XtNhorizDistance, MARGIN,
  340.         XtNborderWidth, 0,
  341.         NULL);
  342.     apply_bitmap(send_toggle, receive_flag ? no_diamond : diamond);
  343.     XtAddCallback(send_toggle, XtNcallback, toggle_receive,
  344.         (XtPointer)&s_false);
  345.     receive_toggle = XtVaCreateManagedWidget(
  346.         "receive", commandWidgetClass, ft_dialog,
  347.         XtNfromVert, send_toggle,
  348.         XtNvertDistance, CLOSE_VGAP,
  349.         XtNhorizDistance, MARGIN,
  350.         XtNborderWidth, 0,
  351.         NULL);
  352.     apply_bitmap(receive_toggle, receive_flag ? diamond : no_diamond);
  353.     XtAddCallback(receive_toggle, XtNcallback, toggle_receive,
  354.         (XtPointer)&s_true);
  355.  
  356.     /* Create ASCII/binary toggles. */
  357.     ascii_toggle = XtVaCreateManagedWidget(
  358.         "ascii", commandWidgetClass, ft_dialog,
  359.         XtNfromVert, receive_toggle,
  360.         XtNvertDistance, FAR_VGAP,
  361.         XtNhorizDistance, MARGIN,
  362.         XtNborderWidth, 0,
  363.         NULL);
  364.     apply_bitmap(ascii_toggle, ascii_flag ? diamond : no_diamond);
  365.     XtAddCallback(ascii_toggle, XtNcallback, toggle_ascii,
  366.         (XtPointer)&s_true);
  367.     binary_toggle = XtVaCreateManagedWidget(
  368.         "binary", commandWidgetClass, ft_dialog,
  369.         XtNfromVert, ascii_toggle,
  370.         XtNvertDistance, CLOSE_VGAP,
  371.         XtNhorizDistance, MARGIN,
  372.         XtNborderWidth, 0,
  373.         NULL);
  374.     apply_bitmap(binary_toggle, ascii_flag ? no_diamond : diamond);
  375.     XtAddCallback(binary_toggle, XtNcallback, toggle_ascii,
  376.         (XtPointer)&s_false);
  377.  
  378.     /* Create append toggle. */
  379.     append_widget = XtVaCreateManagedWidget(
  380.         "append", commandWidgetClass, ft_dialog,
  381.         XtNfromVert, binary_toggle,
  382.         XtNvertDistance, FAR_VGAP,
  383.         XtNhorizDistance, MARGIN,
  384.         XtNborderWidth, 0,
  385.         NULL);
  386.     apply_bitmap(append_widget, append_flag ? dot : null);
  387.     XtAddCallback(append_widget, XtNcallback, toggle_append, NULL);
  388.  
  389.     /* Set up the recfm group. */
  390.     recfm_label = XtVaCreateManagedWidget(
  391.         "file", labelWidgetClass, ft_dialog,
  392.         XtNfromVert, append_widget,
  393.         XtNvertDistance, FAR_VGAP,
  394.         XtNhorizDistance, MARGIN,
  395.         XtNborderWidth, 0,
  396.         NULL);
  397.     register_sensitivity(recfm_label,
  398.         &receive_flag, False,
  399.         BN, False,
  400.         BN, False);
  401.  
  402.     recfm_options[0] = XtVaCreateManagedWidget(
  403.         "recfmDefault", commandWidgetClass, ft_dialog,
  404.         XtNfromVert, recfm_label,
  405.         XtNvertDistance, 3,
  406.         XtNhorizDistance, MARGIN,
  407.         XtNborderWidth, 0,
  408.         NULL);
  409.     apply_bitmap(recfm_options[0],
  410.         (recfm == DEFAULT_RECFM) ? diamond : no_diamond);
  411.     XtAddCallback(recfm_options[0], XtNcallback, recfm_callback,
  412.         (XtPointer)&r_default_recfm);
  413.     register_sensitivity(recfm_options[0],
  414.         &receive_flag, False,
  415.         BN, False,
  416.         BN, False);
  417.  
  418.     recfm_options[1] = XtVaCreateManagedWidget(
  419.         "fixed", commandWidgetClass, ft_dialog,
  420.         XtNfromVert, recfm_options[0],
  421.         XtNvertDistance, CLOSE_VGAP,
  422.         XtNhorizDistance, MARGIN,
  423.         XtNborderWidth, 0,
  424.         NULL);
  425.     apply_bitmap(recfm_options[1],
  426.         (recfm == FIXED) ? diamond : no_diamond);
  427.     XtAddCallback(recfm_options[1], XtNcallback, recfm_callback,
  428.         (XtPointer)&r_fixed);
  429.     register_sensitivity(recfm_options[1],
  430.         &receive_flag, False,
  431.         BN, False,
  432.         BN, False);
  433.  
  434.     recfm_options[2] = XtVaCreateManagedWidget(
  435.         "variable", commandWidgetClass, ft_dialog,
  436.         XtNfromVert, recfm_options[1],
  437.         XtNvertDistance, CLOSE_VGAP,
  438.         XtNhorizDistance, MARGIN,
  439.         XtNborderWidth, 0,
  440.         NULL);
  441.     apply_bitmap(recfm_options[2],
  442.         (recfm == VARIABLE) ? diamond : no_diamond);
  443.     XtAddCallback(recfm_options[2], XtNcallback, recfm_callback,
  444.         (XtPointer)&r_variable);
  445.     register_sensitivity(recfm_options[2],
  446.         &receive_flag, False,
  447.         BN, False,
  448.         BN, False);
  449.  
  450.     recfm_options[3] = XtVaCreateManagedWidget(
  451.         "undefined", commandWidgetClass, ft_dialog,
  452.         XtNfromVert, recfm_options[2],
  453.         XtNvertDistance, CLOSE_VGAP,
  454.         XtNhorizDistance, MARGIN,
  455.         XtNborderWidth, 0,
  456.         NULL);
  457.     apply_bitmap(recfm_options[3],
  458.         (recfm == UNDEFINED) ? diamond : no_diamond);
  459.     XtAddCallback(recfm_options[3], XtNcallback, recfm_callback,
  460.         (XtPointer)&r_undefined);
  461.     register_sensitivity(recfm_options[3],
  462.         &receive_flag, False,
  463.         &vm_flag, False,
  464.         BN, False);
  465.  
  466.     lrecl_label = XtVaCreateManagedWidget(
  467.         "lrecl", labelWidgetClass, ft_dialog,
  468.         XtNfromVert, recfm_options[3],
  469.         XtNvertDistance, 3,
  470.         XtNhorizDistance, MARGIN,
  471.         XtNborderWidth, 0,
  472.         NULL);
  473.     register_sensitivity(lrecl_label,
  474.         &receive_flag, False,
  475.         &recfm_default, False,
  476.         BN, False);
  477.     lrecl_widget = XtVaCreateManagedWidget(
  478.         "value", asciiTextWidgetClass, ft_dialog,
  479.         XtNfromVert, recfm_options[3],
  480.         XtNvertDistance, 3,
  481.         XtNfromHoriz, lrecl_label,
  482.         XtNhorizDistance, MARGIN,
  483.         XtNwidth, 100,
  484.         XtNeditType, XawtextEdit,
  485.         XtNdisplayCaret, False,
  486.         NULL);
  487.     match_dimension(lrecl_label, lrecl_widget, XtNheight);
  488.     w = XawTextGetSource(lrecl_widget);
  489.     if (w == NULL)
  490.         XtWarning("Cannot find text source in dialog");
  491.     else
  492.         XtAddCallback(w, XtNcallback, text_callback,
  493.             (XtPointer)&t_numeric);
  494.     register_sensitivity(lrecl_widget,
  495.         &receive_flag, False,
  496.         &recfm_default, False,
  497.         BN, False);
  498.  
  499.     blksize_label = XtVaCreateManagedWidget(
  500.         "blksize", labelWidgetClass, ft_dialog,
  501.         XtNfromVert, lrecl_widget,
  502.         XtNvertDistance, 3,
  503.         XtNhorizDistance, MARGIN,
  504.         XtNborderWidth, 0,
  505.         NULL);
  506.     match_dimension(blksize_label, lrecl_label, XtNwidth);
  507.     register_sensitivity(blksize_label,
  508.         &receive_flag, False,
  509.         &recfm_default, False,
  510.         BN, False);
  511.     blksize_widget = XtVaCreateManagedWidget(
  512.         "value", asciiTextWidgetClass, ft_dialog,
  513.         XtNfromVert, lrecl_widget,
  514.         XtNvertDistance, 3,
  515.         XtNfromHoriz, blksize_label,
  516.         XtNhorizDistance, MARGIN,
  517.         XtNwidth, 100,
  518.         XtNeditType, XawtextEdit,
  519.         XtNdisplayCaret, False,
  520.         NULL);
  521.     match_dimension(blksize_label, blksize_widget, XtNheight);
  522.     w = XawTextGetSource(blksize_widget);
  523.     if (w == NULL)
  524.         XtWarning("Cannot find text source in dialog");
  525.     else
  526.         XtAddCallback(w, XtNcallback, text_callback,
  527.             (XtPointer)&t_numeric);
  528.     register_sensitivity(blksize_widget,
  529.         &receive_flag, False,
  530.         &recfm_default, False,
  531.         BN, False);
  532.  
  533.  
  534.     /* Find the widest widget in the left column. */
  535.     XtVaGetValues(send_toggle, XtNwidth, &maxw, NULL);
  536.     h_ref = send_toggle;
  537. #define REMAX(w) { \
  538.         XtVaGetValues((w), XtNwidth, &d1, NULL); \
  539.         if (d1 > maxw) { \
  540.             maxw = d1; \
  541.             h_ref = (w); \
  542.         } \
  543.     }
  544.     REMAX(receive_toggle);
  545.     REMAX(ascii_toggle);
  546.     REMAX(binary_toggle);
  547.     REMAX(append_widget);
  548. #undef REMAX
  549.  
  550.     /* Create the right column buttons. */
  551.  
  552.     /* Create VM/TSO toggle. */
  553.     vm_toggle = XtVaCreateManagedWidget(
  554.         "vm", commandWidgetClass, ft_dialog,
  555.         XtNfromVert, host_label,
  556.         XtNvertDistance, FAR_VGAP,
  557.         XtNfromHoriz, h_ref,
  558.         XtNhorizDistance, COLUMN_GAP,
  559.         XtNborderWidth, 0,
  560.         NULL);
  561.     apply_bitmap(vm_toggle, vm_flag ? diamond : no_diamond);
  562.     XtAddCallback(vm_toggle, XtNcallback, toggle_vm, (XtPointer)&s_true);
  563.     tso_toggle =  XtVaCreateManagedWidget(
  564.         "tso", commandWidgetClass, ft_dialog,
  565.         XtNfromVert, vm_toggle,
  566.         XtNvertDistance, CLOSE_VGAP,
  567.         XtNfromHoriz, h_ref,
  568.         XtNhorizDistance, COLUMN_GAP,
  569.         XtNborderWidth, 0,
  570.         NULL);
  571.     apply_bitmap(tso_toggle, vm_flag ? no_diamond : diamond);
  572.     XtAddCallback(tso_toggle, XtNcallback, toggle_vm, (XtPointer)&s_false);
  573.  
  574.     /* Create CR toggle. */
  575.     cr_widget = XtVaCreateManagedWidget(
  576.         "cr", commandWidgetClass, ft_dialog,
  577.         XtNfromVert, tso_toggle,
  578.         XtNvertDistance, FAR_VGAP,
  579.         XtNfromHoriz, h_ref,
  580.         XtNhorizDistance, COLUMN_GAP,
  581.         XtNborderWidth, 0,
  582.         NULL);
  583.     apply_bitmap(cr_widget, cr_flag ? dot : null);
  584.     XtAddCallback(cr_widget, XtNcallback, toggle_cr, 0);
  585.     register_sensitivity(cr_widget,
  586.         &ascii_flag, True,
  587.         BN, False,
  588.         BN, False);
  589.  
  590.     /* Create remap toggle. */
  591.     remap_widget = XtVaCreateManagedWidget(
  592.         "remap", commandWidgetClass, ft_dialog,
  593.         XtNfromVert, cr_widget,
  594.         XtNfromHoriz, h_ref,
  595.         XtNvertDistance, CLOSE_VGAP,
  596.         XtNhorizDistance, COLUMN_GAP,
  597.         XtNborderWidth, 0,
  598.         NULL);
  599.     apply_bitmap(remap_widget, remap_flag ? dot : null);
  600.     XtAddCallback(remap_widget, XtNcallback, toggle_remap, NULL);
  601.     register_sensitivity(remap_widget,
  602.         &ascii_flag, True,
  603.         BN, False,
  604.         BN, False);
  605.  
  606.     /* Set up the Units group. */
  607.     units_label = XtVaCreateManagedWidget(
  608.         "units", labelWidgetClass, ft_dialog,
  609.         XtNfromVert, append_widget,
  610.         XtNvertDistance, FAR_VGAP,
  611.         XtNfromHoriz, h_ref,
  612.         XtNhorizDistance, COLUMN_GAP,
  613.         XtNborderWidth, 0,
  614.         NULL);
  615.     register_sensitivity(units_label,
  616.         &receive_flag, False,
  617.         &vm_flag, False,
  618.         BN, False);
  619.  
  620.     units_options[0] = XtVaCreateManagedWidget(
  621.         "spaceDefault", commandWidgetClass, ft_dialog,
  622.         XtNfromVert, units_label,
  623.         XtNvertDistance, 3,
  624.         XtNfromHoriz, h_ref,
  625.         XtNhorizDistance, COLUMN_GAP,
  626.         XtNborderWidth, 0,
  627.         NULL);
  628.     apply_bitmap(units_options[0],
  629.         (units == DEFAULT_UNITS) ? diamond : no_diamond);
  630.     XtAddCallback(units_options[0], XtNcallback,
  631.         units_callback, (XtPointer)&u_default_units);
  632.     register_sensitivity(units_options[0],
  633.         &receive_flag, False,
  634.         &vm_flag, False,
  635.         BN, False);
  636.  
  637.     units_options[1] = XtVaCreateManagedWidget(
  638.         "tracks", commandWidgetClass, ft_dialog,
  639.         XtNfromVert, units_options[0],
  640.         XtNvertDistance, CLOSE_VGAP,
  641.         XtNfromHoriz, h_ref,
  642.         XtNhorizDistance, COLUMN_GAP,
  643.         XtNborderWidth, 0,
  644.         NULL);
  645.     apply_bitmap(units_options[1],
  646.         (units == TRACKS) ? diamond : no_diamond);
  647.     XtAddCallback(units_options[1], XtNcallback,
  648.         units_callback, (XtPointer)&u_tracks);
  649.     register_sensitivity(units_options[1],
  650.         &receive_flag, False,
  651.         &vm_flag, False,
  652.         BN, False);
  653.  
  654.     units_options[2] = XtVaCreateManagedWidget(
  655.         "cylinders", commandWidgetClass, ft_dialog,
  656.         XtNfromVert, units_options[1],
  657.         XtNvertDistance, CLOSE_VGAP,
  658.         XtNfromHoriz, h_ref,
  659.         XtNhorizDistance, COLUMN_GAP,
  660.         XtNborderWidth, 0,
  661.         NULL);
  662.     apply_bitmap(units_options[2],
  663.         (units == CYLINDERS) ? diamond : no_diamond);
  664.     XtAddCallback(units_options[2], XtNcallback,
  665.         units_callback, (XtPointer)&u_cylinders);
  666.     register_sensitivity(units_options[2],
  667.         &receive_flag, False,
  668.         &vm_flag, False,
  669.         BN, False);
  670.  
  671.     units_options[3] = XtVaCreateManagedWidget(
  672.         "avblock", commandWidgetClass, ft_dialog,
  673.         XtNfromVert, units_options[2],
  674.         XtNvertDistance, CLOSE_VGAP,
  675.         XtNfromHoriz, h_ref,
  676.         XtNhorizDistance, COLUMN_GAP,
  677.         XtNborderWidth, 0,
  678.         NULL);
  679.     apply_bitmap(units_options[3],
  680.         (units == AVBLOCK) ? diamond : no_diamond);
  681.     XtAddCallback(units_options[3], XtNcallback,
  682.         units_callback, (XtPointer)&u_avblock);
  683.     register_sensitivity(units_options[3],
  684.         &receive_flag, False,
  685.         &vm_flag, False,
  686.         BN, False);
  687.  
  688.     primspace_label = XtVaCreateManagedWidget(
  689.         "primspace", labelWidgetClass, ft_dialog,
  690.         XtNfromVert, units_options[3],
  691.         XtNvertDistance, 3,
  692.         XtNfromHoriz, h_ref,
  693.         XtNhorizDistance, COLUMN_GAP,
  694.         XtNborderWidth, 0,
  695.         NULL);
  696.     register_sensitivity(primspace_label,
  697.         &receive_flag, False,
  698.         &vm_flag, False,
  699.         &units_default, False);
  700.     primspace_widget = XtVaCreateManagedWidget(
  701.         "value", asciiTextWidgetClass, ft_dialog,
  702.         XtNfromVert, units_options[3],
  703.         XtNvertDistance, 3,
  704.         XtNfromHoriz, primspace_label,
  705.         XtNhorizDistance, 0,
  706.         XtNwidth, 100,
  707.         XtNeditType, XawtextEdit,
  708.         XtNdisplayCaret, False,
  709.         NULL);
  710.     match_dimension(primspace_label, primspace_widget, XtNheight);
  711.     w = XawTextGetSource(primspace_widget);
  712.     if (w == NULL)
  713.         XtWarning("Cannot find text source in dialog");
  714.     else
  715.         XtAddCallback(w, XtNcallback, text_callback,
  716.             (XtPointer)&t_numeric);
  717.     register_sensitivity(primspace_widget,
  718.         &receive_flag, False,
  719.         &vm_flag, False,
  720.         &units_default, False);
  721.  
  722.     secspace_label = XtVaCreateManagedWidget(
  723.         "secspace", labelWidgetClass, ft_dialog,
  724.         XtNfromVert, primspace_widget,
  725.         XtNvertDistance, 3,
  726.         XtNfromHoriz, h_ref,
  727.         XtNhorizDistance, COLUMN_GAP,
  728.         XtNborderWidth, 0,
  729.         NULL);
  730.     match_dimension(primspace_label, secspace_label, XtNwidth);
  731.     register_sensitivity(secspace_label,
  732.         &receive_flag, False,
  733.         &vm_flag, False,
  734.         &units_default, False);
  735.     secspace_widget = XtVaCreateManagedWidget(
  736.         "value", asciiTextWidgetClass, ft_dialog,
  737.         XtNfromVert, primspace_widget,
  738.         XtNvertDistance, 3,
  739.         XtNfromHoriz, secspace_label,
  740.         XtNhorizDistance, 0,
  741.         XtNwidth, 100,
  742.         XtNeditType, XawtextEdit,
  743.         XtNdisplayCaret, False,
  744.         NULL);
  745.     match_dimension(secspace_label, secspace_widget, XtNheight);
  746.     w = XawTextGetSource(secspace_widget);
  747.     if (w == NULL)
  748.         XtWarning("Cannot find text source in dialog");
  749.     else
  750.         XtAddCallback(w, XtNcallback, text_callback,
  751.             (XtPointer)&t_numeric);
  752.     register_sensitivity(secspace_widget,
  753.         &receive_flag, False,
  754.         &vm_flag, False,
  755.         &units_default, False);
  756.  
  757.     /* Set up the buttons at the bottom. */
  758.     start_button = XtVaCreateManagedWidget(
  759.         ObjConfirmButton, commandWidgetClass, ft_dialog,
  760.         XtNfromVert, blksize_label,
  761.         XtNvertDistance, FAR_VGAP,
  762.         XtNhorizDistance, MARGIN,
  763.         NULL);
  764.     XtAddCallback(start_button, XtNcallback, ft_start_callback,
  765.         (XtPointer)NULL);
  766.  
  767.     cancel_button = XtVaCreateManagedWidget(
  768.         ObjCancelButton, commandWidgetClass, ft_dialog,
  769.         XtNfromVert, blksize_label,
  770.         XtNvertDistance, FAR_VGAP,
  771.         XtNfromHoriz, start_button,
  772.         XtNhorizDistance, BUTTON_GAP,
  773.         NULL);
  774.     XtAddCallback(cancel_button, XtNcallback, ft_cancel, 0);
  775. }
  776.  
  777. /* Callbacks for all the transfer widgets. */
  778.  
  779. /* Transfer pop-up popping up. */
  780. static void
  781. ft_popup_callback(Widget w unused, XtPointer client_data unused,
  782.     XtPointer call_data unused)
  783. {
  784.     /* Set the focus to the local file widget. */
  785.     PA_dialog_focus_action(local_file, (XEvent *)NULL, (String *)NULL,
  786.         (Cardinal *)NULL);
  787.  
  788.     /* Disallow overwrites. */
  789.     allow_overwrite = False;
  790. }
  791.  
  792. /* Cancel button pushed. */
  793. static void
  794. ft_cancel(Widget w unused, XtPointer client_data unused,
  795.     XtPointer call_data unused)
  796. {
  797.     XtPopdown(ft_shell);
  798. }
  799.  
  800. /* recfm options. */
  801. static void
  802. recfm_callback(Widget w, XtPointer user_data, XtPointer call_data unused)
  803. {
  804.     recfm = *(enum recfm *)user_data;
  805.     recfm_default = (recfm == DEFAULT_RECFM);
  806.     check_sensitivity(&recfm_default);
  807.     flip_toggles(&recfm_toggles, w);
  808. }
  809.  
  810. /* Units options. */
  811. static void
  812. units_callback(Widget w, XtPointer user_data, XtPointer call_data unused)
  813. {
  814.     units = *(enum units *)user_data;
  815.     units_default = (units == DEFAULT_UNITS);
  816.     check_sensitivity(&units_default);
  817.     flip_toggles(&units_toggles, w);
  818. }
  819.  
  820. /* OK button pushed. */
  821. static void
  822. ft_start_callback(Widget w unused, XtPointer call_parms unused,
  823.     XtPointer call_data unused)
  824. {
  825.     if (ft_start()) {
  826.         XtPopdown(ft_shell);
  827.         popup_progress();
  828.     }
  829. }
  830.  
  831. /* Mark a toggle. */
  832. static void
  833. mark_toggle(Widget w, Pixmap p)
  834. {
  835.     XtVaSetValues(w, XtNleftBitmap, p, NULL);
  836. }
  837.  
  838. /* Send/receive options. */
  839. static void
  840. toggle_receive(Widget w unused, XtPointer client_data,
  841.     XtPointer call_data unused)
  842. {
  843.     /* Toggle the flag */
  844.     receive_flag = *(Boolean *)client_data;
  845.  
  846.     /* Change the widget states. */
  847.     mark_toggle(receive_toggle, receive_flag ? diamond : no_diamond);
  848.     mark_toggle(send_toggle, receive_flag ? no_diamond : diamond);
  849.     check_sensitivity(&receive_flag);
  850. }
  851.  
  852. /* Ascii/binary options. */
  853. static void
  854. toggle_ascii(Widget w unused, XtPointer client_data, XtPointer call_data unused)
  855. {
  856.     /* Toggle the flag. */
  857.     ascii_flag = *(Boolean *)client_data;
  858.  
  859.     /* Change the widget states. */
  860.     mark_toggle(ascii_toggle, ascii_flag ? diamond : no_diamond);
  861.     mark_toggle(binary_toggle, ascii_flag ? no_diamond : diamond);
  862.     cr_flag = ascii_flag;
  863.     remap_flag = ascii_flag;
  864.     mark_toggle(cr_widget, cr_flag ? dot : null);
  865.     mark_toggle(remap_widget, remap_flag ? dot : null);
  866.     check_sensitivity(&ascii_flag);
  867. }
  868.  
  869. /* CR option. */
  870. static void
  871. toggle_cr(Widget w, XtPointer client_data unused, XtPointer call_data unused)
  872. {
  873.     /* Toggle the cr flag */
  874.     cr_flag = !cr_flag;
  875.  
  876.     mark_toggle(w, cr_flag ? dot : null);
  877. }
  878.  
  879. /* Append option. */
  880. static void
  881. toggle_append(Widget w, XtPointer client_data unused,
  882.     XtPointer call_data unused)
  883. {
  884.     /* Toggle Append Flag */
  885.     append_flag = !append_flag;
  886.  
  887.     mark_toggle(w, append_flag ? dot : null);
  888. }
  889.  
  890. /* Remap option. */
  891. static void
  892. toggle_remap(Widget w, XtPointer client_data unused,
  893.     XtPointer call_data unused)
  894. {
  895.     /* Toggle Remap Flag */
  896.     remap_flag = !remap_flag;
  897.  
  898.     mark_toggle(w, remap_flag ? dot : null);
  899. }
  900.  
  901. /* TSO/VM option. */
  902. static void
  903. toggle_vm(Widget w unused, XtPointer client_data unused,
  904.     XtPointer call_data unused)
  905. {
  906.     /* Toggle the flag. */
  907.     vm_flag = *(Boolean *)client_data;
  908.  
  909.     /* Change the widget states. */
  910.     mark_toggle(vm_toggle, vm_flag ? diamond : no_diamond);
  911.     mark_toggle(tso_toggle, vm_flag ? no_diamond : diamond);
  912.  
  913.     if (vm_flag) {
  914.         if (recfm == UNDEFINED) {
  915.             recfm = DEFAULT_RECFM;
  916.             recfm_default = True;
  917.             flip_toggles(&recfm_toggles,
  918.                 recfm_toggles.widgets[0]);
  919.         }
  920.     }
  921.     check_sensitivity(&vm_flag);
  922. }
  923.  
  924. /*
  925.  * Begin the transfer.
  926.  * Returns 1 if the transfer has started, 0 otherwise.
  927.  */
  928. static int
  929. ft_start(void)
  930. {
  931.     char opts[80];
  932.     char *op = opts + 1;
  933.     char *cmd;
  934.     String lrecl, blksize, primspace, secspace;
  935.     unsigned flen;
  936.  
  937.     ft_is_action = False;
  938.  
  939.     /* Get the host file from its widget */
  940.     XtVaGetValues(host_file, XtNstring, &ft_host_filename, NULL);
  941.     if (!*ft_host_filename)
  942.         return 0;
  943.     /* XXX: probably more validation to do here */
  944.  
  945.     /* Get the local file from it widget */
  946.     XtVaGetValues(local_file, XtNstring,  &ft_local_filename, NULL);
  947.     if (!*ft_local_filename)
  948.         return 0;
  949.  
  950.     /* See if the local file can be overwritten. */
  951.     if (receive_flag && !append_flag && !allow_overwrite) {
  952.         ft_local_file = fopen(ft_local_filename, "r");
  953.         if (ft_local_file != (FILE *)NULL) {
  954.             (void) fclose(ft_local_file);
  955.             ft_local_file = (FILE *)NULL;
  956.             popup_overwrite();
  957.             return 0;
  958.         }
  959.     }
  960.  
  961.     /* Open the local file. */
  962.     ft_local_file = fopen(ft_local_filename,
  963.         receive_flag ?
  964.         (append_flag ? "a" : "w" ) :
  965.         "r");
  966.     if (ft_local_file == (FILE *)NULL) {
  967.         allow_overwrite = False;
  968.         popup_an_errno(errno, "Open(%s)", ft_local_filename);
  969.         return 0;
  970.     }
  971.  
  972.     /* Build the ind$file command */
  973.     op[0] = '\0';
  974.     if (ascii_flag)
  975.         strcat(op, " ascii");
  976.     if (cr_flag)
  977.         strcat(op, " crlf");
  978.     if (append_flag && !receive_flag)
  979.         strcat(op, " append");
  980.     if (!receive_flag) {
  981.         if (!vm_flag) {
  982.             if (recfm != DEFAULT_RECFM) {
  983.                 /* RECFM Entered, process */
  984.                 strcat(op, " recfm(");
  985.                 switch (recfm) {
  986.                     case FIXED:
  987.                     strcat(op, "f");
  988.                     break;
  989.                     case VARIABLE:
  990.                     strcat(op, "v");
  991.                     break;
  992.                     case UNDEFINED:
  993.                     strcat(op, "u");
  994.                     break;
  995.                     default:
  996.                     break;
  997.                 };
  998.                 strcat(op, ")");
  999.                 XtVaGetValues(lrecl_widget,
  1000.                     XtNstring, &lrecl,
  1001.                     NULL);
  1002.                 if (strlen(lrecl) > 0)
  1003.                     sprintf(eos(op), " lrecl(%s)", lrecl);
  1004.                 XtVaGetValues(blksize_widget,
  1005.                     XtNstring, &blksize,
  1006.                     NULL);
  1007.                 if (strlen(blksize) > 0)
  1008.                     sprintf(eos(op), " blksize(%s)",
  1009.                         blksize);
  1010.             }
  1011.             if (units != DEFAULT_UNITS) {
  1012.                 /* Space Entered, processs it */
  1013.                 switch (units) {
  1014.                     case TRACKS:
  1015.                     strcat(op, " tracks");
  1016.                     break;
  1017.                     case CYLINDERS:
  1018.                     strcat(op, " cylinders");
  1019.                     break;
  1020.                     case AVBLOCK:
  1021.                     strcat(op, " avblock");
  1022.                     break;
  1023.                     default:
  1024.                     break;
  1025.                 };
  1026.                 XtVaGetValues(primspace_widget, XtNstring,
  1027.                     &primspace, NULL);
  1028.                 if (strlen(primspace) > 0) {
  1029.                     sprintf(eos(op), " space(%s",
  1030.                         primspace);
  1031.                     XtVaGetValues(secspace_widget,
  1032.                         XtNstring, &secspace,
  1033.                         NULL);
  1034.                     if (strlen(secspace) > 0)
  1035.                         sprintf(eos(op), ",%s",
  1036.                             secspace);
  1037.                     strcat(op, ")");
  1038.                 }
  1039.             }
  1040.         } else {
  1041.             if (recfm != DEFAULT_RECFM) {
  1042.                 strcat(op, " recfm ");
  1043.                 switch (recfm) {
  1044.                     case FIXED:
  1045.                     strcat(op, "f");
  1046.                     break;
  1047.                     case VARIABLE:
  1048.                     strcat(op, "v");
  1049.                     break;
  1050.                     default:
  1051.                     break;
  1052.                 };
  1053.  
  1054.                 XtVaGetValues(lrecl_widget,
  1055.                     XtNstring, &lrecl,
  1056.                     NULL);
  1057.                 if (strlen(lrecl) > 0)
  1058.                     sprintf(eos(op), " lrecl %s", lrecl);
  1059.             }
  1060.         }
  1061.     }
  1062.  
  1063.     /* Insert the '(' for VM options. */
  1064.     if (strlen(op) > 0 && vm_flag) {
  1065.         opts[0] = ' ';
  1066.         opts[1] = '(';
  1067.         op = opts;
  1068.     }
  1069.  
  1070.     /* Build the whole command. */
  1071.     cmd = xs_buffer("%s %s %s%s\\n",
  1072.         appres.ft_command,
  1073.         receive_flag ? "get" : "put", ft_host_filename, op);
  1074.  
  1075.     /* Erase the line and enter the command. */
  1076.     flen = kybd_prime();
  1077.     if (!flen || flen < strlen(cmd) - 1) {
  1078.         XtFree(cmd);
  1079.         popup_an_error(get_message("ftUnable"));
  1080.         allow_overwrite = False;
  1081.         return 0;
  1082.     }
  1083.     (void) emulate_input(cmd, strlen(cmd), False);
  1084.     XtFree(cmd);
  1085.  
  1086.     /* Get this thing started. */
  1087.     ft_state = FT_AWAIT_ACK;
  1088.     ft_is_cut = False;
  1089.  
  1090.     return 1;
  1091. }
  1092.  
  1093. /* "Transfer in Progress" pop-up. */
  1094.  
  1095. /* Pop up the "in progress" pop-up. */
  1096. static void
  1097. popup_progress(void)
  1098. {
  1099.     /* Initialize it. */
  1100.     if (progress_shell == (Widget)NULL)
  1101.         progress_popup_init();
  1102.  
  1103.     /* Pop it up. */
  1104.     popup_popup(progress_shell, XtGrabNone);
  1105. }
  1106.  
  1107. /* Initialize the "in progress" pop-up. */
  1108. static void
  1109. progress_popup_init(void)
  1110. {
  1111.     Widget progress_pop, from_label, to_label, cancel_button;
  1112.  
  1113.     /* Create the shell. */
  1114.     progress_shell = XtVaCreatePopupShell(
  1115.         "ftProgressPopup", transientShellWidgetClass, toplevel,
  1116.         NULL);
  1117.     XtAddCallback(progress_shell, XtNpopupCallback, place_popup,
  1118.         (XtPointer)CenterP);
  1119.     XtAddCallback(progress_shell, XtNpopupCallback,
  1120.         progress_popup_callback, (XtPointer)NULL);
  1121.  
  1122.     /* Create a form structure to contain the other stuff */
  1123.     progress_pop = XtVaCreateManagedWidget(
  1124.         ObjDialog, formWidgetClass, progress_shell,
  1125.         NULL);
  1126.  
  1127.     /* Create the widgets. */
  1128.     from_label = XtVaCreateManagedWidget(
  1129.         "fromLabel", labelWidgetClass, progress_pop,
  1130.         XtNvertDistance, FAR_VGAP,
  1131.         XtNhorizDistance, MARGIN,
  1132.         XtNborderWidth, 0,
  1133.         NULL);
  1134.     from_file = XtVaCreateManagedWidget(
  1135.         "filename", labelWidgetClass, progress_pop,
  1136.         XtNwidth, FILE_WIDTH,
  1137.         XtNvertDistance, FAR_VGAP,
  1138.         XtNfromHoriz, from_label,
  1139.         XtNhorizDistance, 0,
  1140.         NULL);
  1141.     match_dimension(from_label, from_file, XtNheight);
  1142.  
  1143.     to_label = XtVaCreateManagedWidget(
  1144.         "toLabel", labelWidgetClass, progress_pop,
  1145.         XtNfromVert, from_label,
  1146.         XtNvertDistance, FAR_VGAP,
  1147.         XtNhorizDistance, MARGIN,
  1148.         XtNborderWidth, 0,
  1149.         NULL);
  1150.     to_file = XtVaCreateManagedWidget(
  1151.         "filename", labelWidgetClass, progress_pop,
  1152.         XtNwidth, FILE_WIDTH,
  1153.         XtNfromVert, from_label,
  1154.         XtNvertDistance, FAR_VGAP,
  1155.         XtNfromHoriz, to_label,
  1156.         XtNhorizDistance, 0,
  1157.         NULL);
  1158.     match_dimension(to_label, to_file, XtNheight);
  1159.  
  1160.     match_dimension(from_label, to_label, XtNwidth);
  1161.  
  1162.     waiting = XtVaCreateManagedWidget(
  1163.         "waiting", labelWidgetClass, progress_pop,
  1164.         XtNfromVert, to_label,
  1165.         XtNvertDistance, FAR_VGAP,
  1166.         XtNhorizDistance, MARGIN,
  1167.         XtNborderWidth, 0,
  1168.         XtNmappedWhenManaged, False,
  1169.         NULL);
  1170.  
  1171.     ft_status = XtVaCreateManagedWidget(
  1172.         "status", labelWidgetClass, progress_pop,
  1173.         XtNfromVert, to_label,
  1174.         XtNvertDistance, FAR_VGAP,
  1175.         XtNhorizDistance, MARGIN,
  1176.         XtNborderWidth, 0,
  1177.         XtNresizable, True,
  1178.         XtNmappedWhenManaged, False,
  1179.         NULL);
  1180.     XtVaGetValues(ft_status, XtNlabel, &status_string, NULL);
  1181.     status_string = XtNewString(status_string);
  1182.  
  1183.     aborting = XtVaCreateManagedWidget(
  1184.         "aborting", labelWidgetClass, progress_pop,
  1185.         XtNfromVert, to_label,
  1186.         XtNvertDistance, FAR_VGAP,
  1187.         XtNhorizDistance, MARGIN,
  1188.         XtNborderWidth, 0,
  1189.         XtNmappedWhenManaged, False,
  1190.         NULL);
  1191.  
  1192.     cancel_button = XtVaCreateManagedWidget(
  1193.         ObjCancelButton, commandWidgetClass, progress_pop,
  1194.         XtNfromVert, ft_status,
  1195.         XtNvertDistance, FAR_VGAP,
  1196.         XtNhorizDistance, MARGIN,
  1197.         NULL);
  1198.     XtAddCallback(cancel_button, XtNcallback, progress_cancel_callback,
  1199.         NULL);
  1200. }
  1201.  
  1202. /* Callbacks for the "in progress" pop-up. */
  1203.  
  1204. /* In-progress pop-up popped up. */
  1205. static void
  1206. progress_popup_callback(Widget w unused, XtPointer client_data unused,
  1207.     XtPointer call_data unused)
  1208. {
  1209.     XtVaSetValues(from_file, XtNlabel,
  1210.         receive_flag ? ft_host_filename : ft_local_filename, NULL);
  1211.     XtVaSetValues(to_file, XtNlabel,
  1212.         receive_flag ? ft_local_filename : ft_host_filename, NULL);
  1213.  
  1214.     switch (ft_state) {
  1215.         case FT_AWAIT_ACK:
  1216.         XtUnmapWidget(ft_status);
  1217.         XtUnmapWidget(aborting);
  1218.         XtMapWidget(waiting);
  1219.         break;
  1220.         case FT_RUNNING:
  1221.         XtUnmapWidget(waiting);
  1222.         XtUnmapWidget(aborting);
  1223.         XtMapWidget(ft_status);
  1224.         break;
  1225.         case FT_ABORT_WAIT:
  1226.         case FT_ABORT_SENT:
  1227.         XtUnmapWidget(waiting);
  1228.         XtUnmapWidget(ft_status);
  1229.         XtMapWidget(aborting);
  1230.         break;
  1231.         default:
  1232.         break;
  1233.     }
  1234. }
  1235.  
  1236. /* In-progress "cancel" button. */
  1237. static void
  1238. progress_cancel_callback(Widget w unused, XtPointer client_data unused,
  1239.     XtPointer call_data unused)
  1240. {
  1241.     if (ft_state == FT_RUNNING) {
  1242.         ft_state = FT_ABORT_WAIT;
  1243.         XtUnmapWidget(waiting);
  1244.         XtUnmapWidget(ft_status);
  1245.         XtMapWidget(aborting);
  1246.     } else {
  1247.         /* Impatient user or hung host -- just clean up. */
  1248.         ft_complete(get_message("ftUserCancel"));
  1249.     }
  1250. }
  1251.  
  1252. /* "Overwrite existing?" pop-up. */
  1253.  
  1254. /* Pop up the "overwrite" pop-up. */
  1255. static void
  1256. popup_overwrite(void)
  1257. {
  1258.     /* Initialize it. */
  1259.     if (overwrite_shell == (Widget)NULL)
  1260.         overwrite_popup_init();
  1261.  
  1262.     /* Pop it up. */
  1263.     popup_popup(overwrite_shell, XtGrabExclusive);
  1264. }
  1265.  
  1266. /* Initialize the "overwrite" pop-up. */
  1267. static void
  1268. overwrite_popup_init(void)
  1269. {
  1270.     Widget overwrite_pop, overwrite_name, okay_button, cancel_button;
  1271.     String overwrite_string, label, lf;
  1272.     Dimension d;
  1273.  
  1274.     /* Create the shell. */
  1275.     overwrite_shell = XtVaCreatePopupShell(
  1276.         "ftOverwritePopup", transientShellWidgetClass, toplevel,
  1277.         NULL);
  1278.     XtAddCallback(overwrite_shell, XtNpopupCallback, place_popup,
  1279.         (XtPointer)CenterP);
  1280.     XtAddCallback(overwrite_shell, XtNpopdownCallback, overwrite_popdown,
  1281.         (XtPointer)NULL);
  1282.  
  1283.     /* Create a form structure to contain the other stuff */
  1284.     overwrite_pop = XtVaCreateManagedWidget(
  1285.         ObjDialog, formWidgetClass, overwrite_shell,
  1286.         NULL);
  1287.  
  1288.     /* Create the widgets. */
  1289.     overwrite_name = XtVaCreateManagedWidget(
  1290.         "overwriteName", labelWidgetClass, overwrite_pop,
  1291.         XtNvertDistance, MARGIN,
  1292.         XtNhorizDistance, MARGIN,
  1293.         XtNborderWidth, 0,
  1294.         XtNresizable, True,
  1295.         NULL);
  1296.     XtVaGetValues(overwrite_name, XtNlabel, &overwrite_string, NULL);
  1297.     XtVaGetValues(local_file, XtNstring, &lf, NULL);
  1298.     label = xs_buffer(overwrite_string, lf);
  1299.     XtVaSetValues(overwrite_name, XtNlabel, label, NULL);
  1300.     XtFree(label);
  1301.     XtVaGetValues(overwrite_name, XtNwidth, &d, NULL);
  1302.     if ((Dimension)(d + 20) < 400)
  1303.         d = 400;
  1304.     else
  1305.         d += 20;
  1306.     XtVaSetValues(overwrite_name, XtNwidth, d, NULL);
  1307.     XtVaGetValues(overwrite_name, XtNheight, &d, NULL);
  1308.     XtVaSetValues(overwrite_name, XtNheight, d + 20, NULL);
  1309.  
  1310.     okay_button = XtVaCreateManagedWidget(
  1311.         ObjConfirmButton, commandWidgetClass, overwrite_pop,
  1312.         XtNfromVert, overwrite_name,
  1313.         XtNvertDistance, FAR_VGAP,
  1314.         XtNhorizDistance, MARGIN,
  1315.         NULL);
  1316.     XtAddCallback(okay_button, XtNcallback, overwrite_okay_callback,
  1317.         NULL);
  1318.  
  1319.     cancel_button = XtVaCreateManagedWidget(
  1320.         ObjCancelButton, commandWidgetClass, overwrite_pop,
  1321.         XtNfromVert, overwrite_name,
  1322.         XtNvertDistance, FAR_VGAP,
  1323.         XtNfromHoriz, okay_button,
  1324.         XtNhorizDistance, BUTTON_GAP,
  1325.         NULL);
  1326.     XtAddCallback(cancel_button, XtNcallback, overwrite_cancel_callback,
  1327.         NULL);
  1328. }
  1329.  
  1330. /* Overwrite "okay" button. */
  1331. static void
  1332. overwrite_okay_callback(Widget w unused, XtPointer client_data unused,
  1333.     XtPointer call_data unused)
  1334. {
  1335.     XtPopdown(overwrite_shell);
  1336.  
  1337.     allow_overwrite = True;
  1338.     if (ft_start()) {
  1339.         XtPopdown(ft_shell);
  1340.         popup_progress();
  1341.     }
  1342. }
  1343.  
  1344. /* Overwrite "cancel" button. */
  1345. static void
  1346. overwrite_cancel_callback(Widget w unused, XtPointer client_data unused,
  1347.     XtPointer call_data unused)
  1348. {
  1349.     XtPopdown(overwrite_shell);
  1350. }
  1351.  
  1352. /* Overwrite pop-up popped down. */
  1353. static void
  1354. overwrite_popdown(Widget w unused, XtPointer client_data unused,
  1355.     XtPointer call_data unused)
  1356. {
  1357.     XtDestroyWidget(overwrite_shell);
  1358.     overwrite_shell = (Widget)NULL;
  1359. }
  1360. #endif /*]*/
  1361.  
  1362. /* External entry points called by ft_dft and ft_cut. */
  1363.  
  1364. /* Pop up a message, end the transfer. */
  1365. void
  1366. ft_complete(const char *errmsg)
  1367. {
  1368.     /* Close the local file. */
  1369.     if (ft_local_file != (FILE *)NULL && fclose(ft_local_file) < 0)
  1370.         popup_an_errno(errno, "close(%s)", ft_local_filename);
  1371.     ft_local_file = (FILE *)NULL;
  1372.  
  1373.     /* Clean up the state. */
  1374.     ft_state = FT_NONE;
  1375.  
  1376. #if defined(X3270_DISPLAY) && defined(X3270_MENUS) /*[*/
  1377.     /* Pop down the in-progress shell. */
  1378.     XtPopdown(progress_shell);
  1379. #endif /*]*/
  1380.  
  1381.     /* Pop up the text. */
  1382.     if (errmsg != CN) {
  1383.         char *msg_copy = NewString(errmsg);
  1384.  
  1385.         /* Make sure the error message will fit on the display. */
  1386.         if (strlen(msg_copy) > 50 && strchr(msg_copy, '\n') == CN) {
  1387.             char *s = msg_copy + 50;
  1388.  
  1389.             while (s > msg_copy && *s != ' ')
  1390.                 s--;
  1391.             if (s > msg_copy)
  1392.                 *s = '\n';    /* yikes! */
  1393.         }
  1394.         popup_an_error(msg_copy);
  1395.         Free(msg_copy);
  1396.     } else {
  1397.         struct timeval t1;
  1398.         double kbytes_sec;
  1399.         char *buf;
  1400.  
  1401.         (void) gettimeofday(&t1, (struct timezone *)NULL);
  1402.         kbytes_sec = (double)ft_length / 1024.0 /
  1403.             ((double)(t1.tv_sec - t0.tv_sec) + 
  1404.              (double)(t1.tv_usec - t0.tv_usec) / 1.0e6);
  1405.         buf = Malloc(256);
  1406.         (void) sprintf(buf, get_message("ftComplete"), ft_length,
  1407.             kbytes_sec, ft_is_cut ? "CUT" : "DFT");
  1408.         if (ft_is_action) {
  1409.             sms_info(buf);
  1410.             sms_continue();
  1411.         }
  1412. #if defined(X3270_DISPLAY) && defined(X3270_MENUS) /*[*/
  1413.         else
  1414.             popup_an_info(buf);
  1415. #endif /*]*/
  1416.         Free(buf);
  1417.     }
  1418. }
  1419.  
  1420. /* Update the bytes-transferred count on the progress pop-up. */
  1421. void
  1422. ft_update_length(void)
  1423. {
  1424. #if defined(X3270_DISPLAY) && defined(X3270_MENUS) /*[*/
  1425.     char text_string[80];
  1426.  
  1427.     /* Format the message */
  1428.     sprintf(text_string, status_string, ft_length);
  1429.  
  1430.     XtVaSetValues(ft_status, XtNlabel, text_string, NULL);
  1431. #endif /*]*/
  1432. }
  1433.  
  1434. /* Process a transfer acknowledgement. */
  1435. void
  1436. ft_running(Boolean is_cut)
  1437. {
  1438.     if (ft_state == FT_AWAIT_ACK)
  1439.         ft_state = FT_RUNNING;
  1440.     ft_is_cut = is_cut;
  1441.     (void) gettimeofday(&t0, (struct timezone *)NULL);
  1442.     ft_length = 0;
  1443.  
  1444. #if defined(X3270_DISPLAY) && defined(X3270_MENUS) /*[*/
  1445.     XtUnmapWidget(waiting);
  1446. #endif /*]*/
  1447.     ft_update_length();
  1448. #if defined(X3270_DISPLAY) && defined(X3270_MENUS) /*[*/
  1449.     XtMapWidget(ft_status);
  1450. #endif /*]*/
  1451. }
  1452.  
  1453. /* Process a protocol-generated abort. */
  1454. void
  1455. ft_aborting(void)
  1456. {
  1457.     if (ft_state == FT_RUNNING || ft_state == FT_ABORT_WAIT) {
  1458.         ft_state = FT_ABORT_SENT;
  1459. #if defined(X3270_DISPLAY) && defined(X3270_MENUS) /*[*/
  1460.         XtUnmapWidget(waiting);
  1461.         XtUnmapWidget(ft_status);
  1462.         XtMapWidget(aborting);
  1463. #endif /*]*/
  1464.     }
  1465. }
  1466.  
  1467. /* Process a disconnect abort. */
  1468. static void
  1469. ft_connected(Boolean ignored unused)
  1470. {
  1471.     if (!CONNECTED && ft_state != FT_NONE)
  1472.         ft_complete(get_message("ftDisconnected"));
  1473. }
  1474.  
  1475. /* Process an abort from no longer being in 3270 mode. */
  1476. static void
  1477. ft_in3270(Boolean ignored unused)
  1478. {
  1479.     if (!IN_3270 && ft_state != FT_NONE)
  1480.         ft_complete(get_message("ftNot3270"));
  1481. }
  1482.  
  1483. #if defined(X3270_DISPLAY) && defined(X3270_MENUS) /*[*/
  1484. /* Support functions for dialogs. */
  1485.  
  1486. /* Match one dimension of two widgets. */
  1487. static void
  1488. match_dimension(Widget w1, Widget w2, const char *n)
  1489. {
  1490.     Dimension h1, h2;
  1491.     Dimension b1, b2;
  1492.  
  1493.     XtVaGetValues(w1, n, &h1, XtNborderWidth, &b1, NULL);
  1494.     XtVaGetValues(w2, n, &h2, XtNborderWidth, &b2, NULL);
  1495.     h1 += 2 * b1;
  1496.     h2 += 2 * b2;
  1497.     if (h1 > h2)
  1498.         XtVaSetValues(w2, n, h1 - (2 * b2), NULL);
  1499.     else if (h2 > h1)
  1500.         XtVaSetValues(w1, n, h2 - (2 * b1), NULL);
  1501. }
  1502.  
  1503. /* Apply a bitmap to a widget. */
  1504. static void
  1505. apply_bitmap(Widget w, Pixmap p)
  1506. {
  1507.     Dimension d1;
  1508.  
  1509.     XtVaGetValues(w, XtNheight, &d1, NULL);
  1510.     if (d1 < 10)
  1511.         XtVaSetValues(w, XtNheight, 10, NULL);
  1512.     XtVaSetValues(w, XtNleftBitmap, p, NULL);
  1513. }
  1514.  
  1515. /* Flip a multi-valued toggle. */
  1516. static void
  1517. flip_toggles(struct toggle_list *toggle_list, Widget w)
  1518. {
  1519.     int i;
  1520.  
  1521.     /* Flip the widget w to on, and the rest to off. */
  1522.     for (i = 0; toggle_list->widgets[i] != (Widget)NULL; i++) {
  1523.         /* Process each widget in the list */
  1524.         mark_toggle(*(toggle_list->widgets+i),
  1525.             (*(toggle_list->widgets+i) == w) ? diamond : no_diamond);
  1526.     }
  1527. }
  1528.  
  1529. /*
  1530.  * Callback for text source changes.  Edits the text to ensure it meets the
  1531.  * specified criteria.
  1532.  */
  1533. static void
  1534. text_callback(Widget w, XtPointer client_data, XtPointer call_data unused)
  1535. {
  1536.     XawTextBlock b;        /* firstPos, length, ptr, format */
  1537.     static XawTextBlock nullb = { 0, 0, NULL };
  1538.     XawTextPosition pos = 0;
  1539.     int i;
  1540.     text_t t = *(text_t *)client_data;
  1541.     static Boolean called_back = False;
  1542.  
  1543.     if (called_back)
  1544.         return;
  1545.     else
  1546.         called_back = True;
  1547.  
  1548.     while (1) {
  1549.         Boolean replaced = False;
  1550.  
  1551.         XawTextSourceRead(w, pos, &b, 1024);
  1552.         if (b.length <= 0)
  1553.             break;
  1554.         nullb.format = b.format;
  1555.         for (i = 0; i < b.length; i++) {
  1556.             Boolean bad = False;
  1557.             char c = *(b.ptr + i);
  1558.  
  1559.             switch (t) {
  1560.                 case T_NUMERIC:
  1561.                 /* Only numbers. */
  1562.                 bad = !isdigit(c);
  1563.                 break;
  1564.                 case T_HOSTFILE:
  1565.                 /*
  1566.                  * Only printing characters and spaces; no
  1567.                  * leading or trailing blanks.
  1568.                  */
  1569.                 bad = !isprint(c) || (!pos && !i && c == ' ');
  1570.                 break;
  1571.                 case T_UNIXFILE:
  1572.                 /* Only printing characters. */
  1573.                 bad = !isgraph(c);
  1574.                 break;
  1575.             }
  1576.             if (bad) {
  1577.                 XawTextSourceReplace(w, pos + i, pos + i + 1,
  1578.                     &nullb);
  1579.                 pos = 0;
  1580.                 replaced = True;
  1581.                 break;
  1582.             }
  1583.         }
  1584.         if (replaced)
  1585.             continue; /* rescan the same block */
  1586.         pos += b.length;
  1587.         if (b.length < 1024)
  1588.             break;
  1589.     }
  1590.     called_back = False;
  1591. }
  1592.  
  1593. /* Register widget sensitivity, based on zero to three Booleans. */
  1594. static void
  1595. register_sensitivity(Widget w, Boolean *bvar1, Boolean bval1, Boolean *bvar2,
  1596.     Boolean bval2, Boolean *bvar3, Boolean bval3)
  1597. {
  1598.     sr_t *s;
  1599.     Boolean f;
  1600.  
  1601.     /* Allocate a structure. */
  1602.     s = (sr_t *)XtMalloc(sizeof(sr_t));
  1603.     s->w = w;
  1604.     s->bvar1 = bvar1;
  1605.     s->bval1 = bval1;
  1606.     s->bvar2 = bvar2;
  1607.     s->bval2 = bval2;
  1608.     s->bvar3 = bvar3;
  1609.     s->bval3 = bval3;
  1610.     s->is_value = !strcmp(XtName(w), "value");
  1611.     s->has_focus = False;
  1612.  
  1613.     /* Link it onto the chain. */
  1614.     s->next = (sr_t *)NULL;
  1615.     if (sr_last != (sr_t *)NULL)
  1616.         sr_last->next = s;
  1617.     else
  1618.         sr = s;
  1619.     sr_last = s;
  1620.  
  1621.     /* Set up the initial widget sensitivity. */
  1622.     if (bvar1 == (Boolean *)NULL)
  1623.         f = True;
  1624.     else {
  1625.         f = (*bvar1 == bval1);
  1626.         if (bvar2 != (Boolean *)NULL)
  1627.             f &= (*bvar2 == bval2);
  1628.         if (bvar3 != (Boolean *)NULL)
  1629.             f &= (*bvar3 == bval3);
  1630.     }
  1631.     XtVaSetValues(w, XtNsensitive, f, NULL);
  1632. }
  1633.  
  1634. /* Scan the list of registered widgets for a sensitivity change. */
  1635. static void
  1636. check_sensitivity(Boolean *bvar)
  1637. {
  1638.     sr_t *s;
  1639.  
  1640.     for (s = sr; s != (sr_t *)NULL; s = s->next) {
  1641.         if (s->bvar1 == bvar || s->bvar2 == bvar || s->bvar3 == bvar) {
  1642.             Boolean f;
  1643.  
  1644.             f = (s->bvar1 != (Boolean *)NULL &&
  1645.                  (*s->bvar1 == s->bval1));
  1646.             if (s->bvar2 != (Boolean *)NULL)
  1647.                 f &= (*s->bvar2 == s->bval2);
  1648.             if (s->bvar3 != (Boolean *)NULL)
  1649.                 f &= (*s->bvar3 == s->bval3);
  1650.             XtVaSetValues(s->w, XtNsensitive, f, NULL);
  1651.  
  1652.             /* If it is now insensitive, move the focus. */
  1653.             if (!f && s->is_value && s->has_focus)
  1654.                 focus_next(s);
  1655.         }
  1656.     }
  1657. }
  1658.  
  1659. /* Move the input focus to the next sensitive value field. */
  1660. static void
  1661. focus_next(sr_t *s)
  1662. {
  1663.     sr_t *t;
  1664.     Boolean sen;
  1665.  
  1666.     /* Defocus this widget. */
  1667.     s->has_focus = False;
  1668.     XawTextDisplayCaret(s->w, False);
  1669.  
  1670.     /* Search after. */
  1671.     for (t = s->next; t != (sr_t *)NULL; t = t->next) {
  1672.         if (t->is_value) {
  1673.             XtVaGetValues(t->w, XtNsensitive, &sen, NULL);
  1674.             if (sen)
  1675.                 break;
  1676.         }
  1677.     }
  1678.  
  1679.     /* Wrap and search before. */
  1680.     if (t == (sr_t *)NULL)
  1681.         for (t = sr; t != s && t != (sr_t *)NULL; t = t->next) {
  1682.             if (t->is_value) {
  1683.                 XtVaGetValues(t->w, XtNsensitive, &sen, NULL);
  1684.                 if (sen)
  1685.                     break;
  1686.             }
  1687.         }
  1688.  
  1689.     /* Move the focus. */
  1690.     if (t != (sr_t *)NULL && t != s) {
  1691.         t->has_focus = True;
  1692.         XawTextDisplayCaret(t->w, True);
  1693.         XtSetKeyboardFocus(ft_dialog, t->w);
  1694.     }
  1695. }
  1696.  
  1697. /* Dialog action procedures. */
  1698.  
  1699. /* Proceed to the next input field. */
  1700. void
  1701. PA_dialog_next_action(Widget w, XEvent *event unused, String *parms unused,
  1702.     Cardinal *num_parms unused)
  1703. {
  1704.     sr_t *s;
  1705.  
  1706.     for (s = sr; s != (sr_t *)NULL; s = s->next) {
  1707.         if (s->w == w) {
  1708.             focus_next(s);
  1709.             return;
  1710.         }
  1711.     }
  1712. }
  1713.  
  1714. /* Set keyboard focus to an input field. */
  1715. void
  1716. PA_dialog_focus_action(Widget w, XEvent *event unused, String *parms unused,
  1717.     Cardinal *num_parms unused)
  1718. {
  1719.     sr_t *s;
  1720.  
  1721.     /* Remove the focus from the widget that has it now. */
  1722.     for (s = sr; s != (sr_t *)NULL; s = s->next) {
  1723.         if (s->has_focus) {
  1724.             if (s->w == w)
  1725.                 return;
  1726.             s->has_focus = False;
  1727.             XawTextDisplayCaret(s->w, False);
  1728.             break;
  1729.         }
  1730.     }
  1731.  
  1732.     /* Find this object. */
  1733.     for (s = sr; s != (sr_t *)NULL; s = s->next) {
  1734.         if (s->w == w)
  1735.             break;
  1736.     }
  1737.     if (s == (sr_t *)NULL)
  1738.         return;
  1739.  
  1740.     /* Give it the focus. */
  1741.     s->has_focus = True;
  1742.     XawTextDisplayCaret(w, True);
  1743.     XtSetKeyboardFocus(ft_dialog, w);
  1744. }
  1745. #endif /*]*/
  1746.  
  1747. /*
  1748.  * Script/macro action for file transfer.
  1749.  *  Transfer(option=value[,...])
  1750.  *  Options are:
  1751.  *   Direction=send|receive    default receive
  1752.  *   HostFile=name        required
  1753.  *   LocalFile=name            required
  1754.  *   Host=[tso|vm]        default tso
  1755.  *   Mode=[ascii|binary]    default ascii
  1756.  *   Cr=[add|remove|keep]    default add/remove
  1757.  *   Exist=[keep|replace|append]    default keep
  1758.  *   Recfm=[default|fixed|variable|undefined] default default
  1759.  *   Lrecl=n            no default
  1760.  *   Blksize=n            no default
  1761.  *   Allocation=[default|tracks|cylinders|avblock] default default
  1762.  *   PrimarySpace=n        no default
  1763.  *   SecondarySpace=n        no default
  1764.  */
  1765. static struct {
  1766.     const char *name;
  1767.     char *value;
  1768.     const char *keyword[4];
  1769. } tp[] = {
  1770.     { "Direction",        CN, { "receive", "send" } },
  1771.     { "HostFile" },
  1772.     { "LocalFile" },
  1773.     { "Host",        CN, { "tso", "vm" } },
  1774.     { "Mode",        CN, { "ascii", "binary" } },
  1775.     { "Cr",            CN, { "remove",    "add", "keep" } },
  1776.     { "Exist",        CN, { "keep", "replace", "append" } },
  1777.     { "Recfm",        CN, { "default", "fixed", "variable",
  1778.                       "undefined" } },
  1779.     { "Lrecl" },
  1780.     { "Blksize" },
  1781.     { "Allocation",        CN, { "default", "tracks", "cylinders",
  1782.                       "avblock" } },
  1783.     { "PrimarySpace" },
  1784.     { "SecondarySpace" },
  1785.     { CN }
  1786. };
  1787. #define PARM_DIRECTION        0
  1788. #define PARM_HOST_FILE        1
  1789. #define PARM_LOCAL_FILE        2
  1790. #define PARM_HOST        3
  1791. #define PARM_MODE        4
  1792. #define PARM_CR            5
  1793. #define PARM_EXIST        6
  1794. #define PARM_RECFM        7
  1795. #define PARM_LRECL        8
  1796. #define PARM_BLKSIZE        9
  1797. #define PARM_ALLOCATION        10
  1798. #define PARM_PRIMARY_SPACE    11
  1799. #define PARM_SECONDARY_SPACE    12
  1800. #define N_PARMS            (PARM_SECONDARY_SPACE + 1)
  1801.  
  1802. void  
  1803. Transfer_action(Widget w unused, XEvent *event, String *params,
  1804.     Cardinal *num_params)
  1805. {
  1806.     int i, k;
  1807.     Cardinal j;
  1808.     long l;
  1809.     char *ptr;
  1810.  
  1811.     char opts[80];
  1812.     char *op = opts + 1;
  1813.     char *cmd;
  1814.     unsigned flen;
  1815.  
  1816.         action_debug(Transfer_action, event, params, num_params);
  1817.  
  1818.     ft_is_action = True;
  1819.  
  1820.     /* Make sure we're connected. */
  1821.     if (!IN_3270) {
  1822.         popup_an_error("Not connected");
  1823.         return;
  1824.     }
  1825.  
  1826.     /* Set everything to the default. */
  1827.     for (i = 0; i < N_PARMS; i++) {
  1828.         if (tp[i].value != CN)
  1829.             Free(tp[i].value);
  1830.         if (tp[i].keyword[0] != CN)
  1831.             tp[i].value =
  1832.                 NewString(tp[i].keyword[0]);
  1833.         else
  1834.             tp[i].value = CN;
  1835.     }
  1836.  
  1837.     /* See what they specified. */
  1838.     for (j = 0; j < *num_params; j++) {
  1839.         for (i = 0; i < N_PARMS; i++) {
  1840.             char *eq;
  1841.             int kwlen;
  1842.  
  1843.             eq = strchr(params[j], '=');
  1844.             if (eq == CN || eq == params[j] || !*(eq + 1)) {
  1845.                 popup_an_error("Invalid option syntax: '%s'",
  1846.                     params[j]);
  1847.                 return;
  1848.             }
  1849.             kwlen = eq - params[j];
  1850. #ifndef AMIGA
  1851.             if (!strncasecmp(params[j], tp[i].name, kwlen)
  1852. #else
  1853.             if (!strncmp(params[j], tp[i].name, kwlen)
  1854. #endif
  1855.                     && !tp[i].name[kwlen]) {
  1856.                 if (tp[i].keyword[0]) {
  1857.                     for (k = 0;
  1858.                          tp[i].keyword[k] != CN && k < 4;
  1859.                          k++) {
  1860.                         if (!strcasecmp(eq + 1,
  1861.                             tp[i].keyword[k])) {
  1862.                             break;
  1863.                         }
  1864.                     }
  1865.                     if (k >= 4 ||
  1866.                         tp[i].keyword[k] == CN) {
  1867.                         popup_an_error("Invalid option "
  1868.                             "value: '%s'", eq + 1);
  1869.                         return;
  1870.                     }
  1871.                 } else switch (i) {
  1872.                     case PARM_LRECL:
  1873.                     case PARM_BLKSIZE:
  1874.                     case PARM_PRIMARY_SPACE:
  1875.                     case PARM_SECONDARY_SPACE:
  1876.                     l = strtol(eq + 1, &ptr, 10);
  1877.                     if (ptr == eq + 1 || !*ptr) {
  1878.                         popup_an_error("Invalid option "
  1879.                             "value: '%s'", eq + 1);
  1880.                         return;
  1881.                     }
  1882.                     break;
  1883.                     default:
  1884.                     break;
  1885.                 }
  1886.                 tp[i].value = NewString(eq + 1);
  1887.                 break;
  1888.             }
  1889.         }
  1890.         if (i >= N_PARMS) {
  1891.             popup_an_error("Unknown option: %s", params[j]);
  1892.             return;
  1893.         }
  1894.     }
  1895.  
  1896.     /* Check for required values. */
  1897.     if (tp[PARM_HOST_FILE].value == CN) {
  1898.         popup_an_error("Missing 'HostFile' option");
  1899.         return;
  1900.     }
  1901.     if (tp[PARM_LOCAL_FILE].value == CN) {
  1902.         popup_an_error("Missing 'LocalFile' option");
  1903.         return;
  1904.     }
  1905.  
  1906.     /*
  1907.      * Start the transfer.  Much of this is duplicated from ft_start()
  1908.      * and should be made common.
  1909.      */
  1910.  
  1911.     receive_flag = !strcasecmp(tp[PARM_DIRECTION].value, "receive");
  1912.     append_flag = !strcasecmp(tp[PARM_EXIST].value, "append");
  1913.     allow_overwrite = !strcasecmp(tp[PARM_EXIST].value, "replace");
  1914.     ascii_flag = !strcasecmp(tp[PARM_MODE].value, "ascii");
  1915.     cr_flag = !strcasecmp(tp[PARM_CR].value, "remove") ||
  1916.           !strcasecmp(tp[PARM_CR].value, "add");
  1917.     vm_flag = !strcasecmp(tp[PARM_HOST].value, "vm");
  1918.     recfm = DEFAULT_RECFM;
  1919.     for (k = 0; tp[PARM_RECFM].keyword[k] != CN && k < 4; k++) {
  1920.         if (!strcasecmp(tp[PARM_RECFM].value,
  1921.                 tp[PARM_RECFM].keyword[k]))  {
  1922.             recfm = (enum recfm)k;
  1923.             break;
  1924.         }
  1925.     }
  1926.     units = DEFAULT_UNITS;
  1927.     for (k = 0; tp[PARM_ALLOCATION].keyword[k] != CN && k < 4; k++) {
  1928.         if (!strcasecmp(tp[PARM_ALLOCATION].value,
  1929.                 tp[PARM_ALLOCATION].keyword[k]))  {
  1930.             units = (enum units)k;
  1931.             break;
  1932.         }
  1933.     }
  1934.  
  1935.     ft_host_filename = tp[PARM_HOST_FILE].value;
  1936.     ft_local_filename = tp[PARM_LOCAL_FILE].value;
  1937.  
  1938.     /* See if the local file can be overwritten. */
  1939.     if (receive_flag && !append_flag && !allow_overwrite) {
  1940.         ft_local_file = fopen(ft_local_filename, "r");
  1941.         if (ft_local_file != (FILE *)NULL) {
  1942.             (void) fclose(ft_local_file);
  1943.             popup_an_error("File exists");
  1944.             return;
  1945.         }
  1946.     }
  1947.  
  1948.     /* Open the local file. */
  1949.     ft_local_file = fopen(ft_local_filename,
  1950.         receive_flag ?
  1951.         (append_flag ? "a" : "w" ) :
  1952.         "r");
  1953.     if (ft_local_file == (FILE *)NULL) {
  1954.         popup_an_errno(errno, "Open(%s)", ft_local_filename);
  1955.         return;
  1956.     }
  1957.  
  1958.     /* Build the ind$file command */
  1959.     op[0] = '\0';
  1960.     if (ascii_flag)
  1961.         strcat(op, " ascii");
  1962.     if (cr_flag)
  1963.         strcat(op, " crlf");
  1964.     if (append_flag && !receive_flag)
  1965.         strcat(op, " append");
  1966.     if (!receive_flag) {
  1967.         if (!vm_flag) {
  1968.             if (recfm != DEFAULT_RECFM) {
  1969.                 /* RECFM Entered, process */
  1970.                 strcat(op, " recfm(");
  1971.                 switch (recfm) {
  1972.                     case FIXED:
  1973.                     strcat(op, "f");
  1974.                     break;
  1975.                     case VARIABLE:
  1976.                     strcat(op, "v");
  1977.                     break;
  1978.                     case UNDEFINED:
  1979.                     strcat(op, "u");
  1980.                     break;
  1981.                     default:
  1982.                     break;
  1983.                 };
  1984.                 strcat(op, ")");
  1985.                 if (tp[PARM_LRECL].value != CN)
  1986.                     sprintf(eos(op), " lrecl(%s)",
  1987.                         tp[PARM_LRECL].value);
  1988.                 if (tp[PARM_BLKSIZE].value != CN)
  1989.                     sprintf(eos(op), " blksize(%s)",
  1990.                         tp[PARM_BLKSIZE].value);
  1991.             }
  1992.             if (units != DEFAULT_UNITS) {
  1993.                 /* Space Entered, processs it */
  1994.                 switch (units) {
  1995.                     case TRACKS:
  1996.                     strcat(op, " tracks");
  1997.                     break;
  1998.                     case CYLINDERS:
  1999.                     strcat(op, " cylinders");
  2000.                     break;
  2001.                     case AVBLOCK:
  2002.                     strcat(op, " avblock");
  2003.                     break;
  2004.                     default:
  2005.                     break;
  2006.                 };
  2007.                 if (tp[PARM_PRIMARY_SPACE].value != CN) {
  2008.                     sprintf(eos(op), " space(%s",
  2009.                         tp[PARM_PRIMARY_SPACE].value);
  2010.                     if (tp[PARM_SECONDARY_SPACE].value)
  2011.                         sprintf(eos(op), ",%s",
  2012.                             tp[PARM_SECONDARY_SPACE].value);
  2013.                     strcat(op, ")");
  2014.                 }
  2015.             }
  2016.         } else {
  2017.             if (recfm != DEFAULT_RECFM) {
  2018.                 strcat(op, " recfm ");
  2019.                 switch (recfm) {
  2020.                     case FIXED:
  2021.                     strcat(op, "f");
  2022.                     break;
  2023.                     case VARIABLE:
  2024.                     strcat(op, "v");
  2025.                     break;
  2026.                     default:
  2027.                     break;
  2028.                 };
  2029.  
  2030.                 if (tp[PARM_LRECL].value)
  2031.                     sprintf(eos(op), " lrecl %s",
  2032.                         tp[PARM_LRECL].value);
  2033.             }
  2034.         }
  2035.     }
  2036.  
  2037.     /* Insert the '(' for VM options. */
  2038.     if (strlen(op) > 0 && vm_flag) {
  2039.         opts[0] = ' ';
  2040.         opts[1] = '(';
  2041.         op = opts;
  2042.     }
  2043.  
  2044.     /* Build the whole command. */
  2045.     cmd = xs_buffer("%s %s %s%s\\n",
  2046.         appres.ft_command,
  2047.         receive_flag ? "get" : "put", ft_host_filename, op);
  2048.  
  2049.     /* Erase the line and enter the command. */
  2050.     flen = kybd_prime();
  2051.     if (!flen || flen < strlen(cmd) - 1) {
  2052.         Free(cmd);
  2053.         popup_an_error(get_message("ftUnable"));
  2054.         return;
  2055.     }
  2056.     (void) emulate_input(cmd, strlen(cmd), False);
  2057.     Free(cmd);
  2058.  
  2059.     /* Get this thing started. */
  2060.     ft_state = FT_AWAIT_ACK;
  2061.     ft_is_cut = False;
  2062.  
  2063.     /* Start tracking it. */
  2064. #if defined(X3270_DISPLAY) && defined(X3270_MENUS) /*[*/
  2065.     popup_progress();
  2066. #endif /*]*/
  2067. }
  2068.  
  2069. #endif /*]*/
  2070.